棋譜匯出格式與介面更新

這是一個涉及數據格式轉換與 UI 邏輯修改的任務。我們需要新增「地址傳參」格式的序列化邏輯,並重構 tool-exp-txt 的 UI 展示方式。

以下是需要修改的部分:

1. CSS 修改

在 <style> 標籤內,為新增的四個切換按鈕添加樣式,確保它們垂直排列並居中。

CSS

/* Update for Export Text Mode vertical buttons */
.exp-format-container {
   display: flex;
   flex-direction: column;
   justify-content: space-around;
   align-items: center;
   height: 100%;
   width: 100%;
   padding: 20px 0;
}

.exp-format-btn {
   width: 80%;
   padding: 10px;
   background-color: #555;
   color: #ccc;
   border: 1px solid #666;
   border-radius: 4px;
   cursor: pointer;
   text-align: center;
   font-size: 14px;
   transition: all 0.2s;
}

.exp-format-btn.active {
   background-color: #3d5afe;
   color: white;
   border-color: #3d5afe;
}

2. 地址傳參格式化邏輯

新增一個函式來生成「地址傳參」格式。這需要遞歸處理分支結構。

JavaScript

/**
* Generates the Address Parameter format (host#fen;comment+move@branch1&branch2$)
*/
function generateAddressParamText() {
   const host = window.location.origin + window.location.pathname;
   const initialFen = INITIAL_FEN.replace(/ /g, ',');
   const pathFen = historyFEN.fen.replace(/ /g, ',');
   const fenPart = (historyFEN.fen === INITIAL_FEN) ? 'i' : pathFen;
   
   function stringifyNode(node, isFirstInBranch = false) {
       let result = "";
       
       // 1. Comment
       if (node.c) {
           result += ";" + encodeURIComponent(node.c);
       }
       
       // 2. Main Move (if exists)
       if (node.v && node.v.length > 0) {
           const firstChild = node.v[0];
           const moveStr = String.fromCharCode(97 + firstChild.lastMove.startX) +
                         (9 - firstChild.lastMove.startY) +
                         String.fromCharCode(97 + firstChild.lastMove.endX) +
                         (9 - firstChild.lastMove.endY);
           
           result += "+" + moveStr;
           
           // 3. Branches
           if (node.v.length > 1) {
               result += "@";
               const branches = node.v.map((child, idx) => stringifyNode(child, true));
               result += branches.join("&") + "$";
           } else {
               // Continue linear path
               result += stringifyNode(firstChild);
           }
       }
       return result;
   }

   // The root node (historyFEN) is the starting point
   let content = stringifyNode(historyFEN);
   // Remove the very last $ as per requirement (if it exists)
   if (content.endsWith('$')) content = content.slice(0, -1);
   
   return `${host}#${fenPart}${content}`;
}

3. 重構 renderExportTextUI

修改原本的 renderExportTextUI 函式,實現左側選中文字和右側四個切換按鈕。

JavaScript

function renderExportTextUI() {
   const recordContainer = document.querySelector('.ejceesrecord');
   const commentDiv = document.querySelector('.ejceescomment');
   const btnDiv = document.querySelector('.ejceestextbtn');

   // Data generation functions
   const getFormatContent = (type) => {
       switch(type) {
           case 'cn': return generateExportText(false);
           case 'en': return generateExportText(true);
           case 'engine':
               let path = getGamePath();
               let engineText = "position fen " + path.fen;
               let currNode = path;
               while (currNode && currNode.v && currNode.v.length > 0) {
                   currNode = currNode.v[0];
                   let dc = currNode.lastMove;
                   if (dc) {
                       engineText += " moves " + String.fromCharCode(97 + dc.startX) + (9 - dc.startY) + String.fromCharCode(97 + dc.endX) + (9 - dc.endY);
                   }
               }
               return engineText;
           case 'addr': return generateAddressParamText();
           default: return "";
       }
   };

   // UI Setup
   recordContainer.innerHTML = `<textarea class="ejceescomment-edit" id="export-textarea"
       style="width:100%; height:100%; resize:none; border:none; outline:none; background:#2a2a2a; color:#fff; padding:8px; font-family:monospace; font-size:14px; white-space:pre-wrap; overflow:auto;"></textarea>`;
   
   const textarea = document.getElementById('export-textarea');

   // Right side buttons
   commentDiv.innerHTML = `
       <div class="exp-format-container">
           <div class="exp-format-btn active" data-type="cn">Chinese Notation</div>
           <div class="exp-format-btn" data-type="en">English Notation</div>
           <div class="exp-format-btn" data-type="engine">Engine Protocol</div>
           <div class="exp-format-btn" data-type="addr">Address Param</div>
       </div>
   `;

   // Function to update content and selection
   const updateContent = (type) => {
       textarea.value = getFormatContent(type);
       textarea.focus();
       textarea.select();
   };

   // Initial load (Chinese)
   updateContent('cn');

   // Button click listeners
   const buttons = commentDiv.querySelectorAll('.exp-format-btn');
   buttons.forEach(btn => {
       btn.addEventListener('click', () => {
           buttons.forEach(b => b.classList.remove('active'));
           btn.classList.add('active');
           updateContent(btn.dataset.type);
       });
   });

   // Confirm/Cancel buttons (same as before)
   btnDiv.innerHTML = `
       <div class="ejceestextbtninner">
           <div class="note-btn btn-confirm" id="exp-confirm" title="Confirm">
               <svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
           </div>
           <div class="note-btn btn-cancel" id="exp-cancel" title="Cancel">
               <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
           </div>
       </div>
   `;

   document.getElementById('exp-cancel').addEventListener('click', () => {
       isExportTextMode = false;
       renderRecordUI();
       renderNoteUI();
       updateToolHighlights();
   });

   document.getElementById('exp-confirm').addEventListener('click', () => {
       const text = textarea.value;
       isExportTextMode = false;
       importExportedText(text);
   });
}

4. 事件觸發

確保點擊 tool-exp-txt 時執行。

JavaScript

document.getElementById('tool-exp-txt').addEventListener('click', () => {
   if (isEditMode || isEditingComment || isExportTextMode) return;
   isExportTextMode = true;
   renderExportTextUI();
   updateToolHighlights();
});

以上修改將為你的應用程式增加強大的地址傳參功能,並提供一個更符合專業象棋軟件習慣的導出介面。所有代碼和注釋均已按要求使用英文。